using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace libACO
{
    class LimitedFileStream : FileStream
    {
        private FileStream mBaseStream;
        private long mStartOffset;
        private long mLength;

        public LimitedFileStream(FileStream BaseStream, long StartOffset, long Length)
            : base(BaseStream.SafeFileHandle, FileAccess.Read)
        {
            mBaseStream = BaseStream;
            mStartOffset = StartOffset;
            mLength = Length;
            
            BSeek(0, SeekOrigin.Begin);
        }

        public LimitedFileStream(string FileName, long StartOffset, long Length)
            : base(FileName, FileMode.Open, FileAccess.Read, FileShare.Read)
        {
            mBaseStream = null;
            mStartOffset = StartOffset;
            mLength = Length;

            BSeek(0, SeekOrigin.Begin);
        }

        private long BSeek(long Position, SeekOrigin Origin)
        {
            switch (Origin)
            {
                case SeekOrigin.Begin:
                    if (Position < mLength)
                    {
                        if(mBaseStream == null)
                            return base.Seek(mStartOffset + Position, SeekOrigin.Begin);
                        else
                            return mBaseStream.Seek(mStartOffset + Position, SeekOrigin.Begin);
                    }
                    break;
                case SeekOrigin.Current:
                    if (mBaseStream.Position + Position < mStartOffset + mLength)
                    {
                        if (mBaseStream == null)
                            return base.Seek(Position, SeekOrigin.Current);
                        else
                            return mBaseStream.Seek(Position, SeekOrigin.Current);
                    }
                    break;
                case SeekOrigin.End:
                    if (Position < mLength)
                    {
                        if (mBaseStream == null)
                            return base.Seek(mStartOffset + mLength - Position, SeekOrigin.End);
                        else
                            return mBaseStream.Seek(mStartOffset + mLength - Position, SeekOrigin.End);
                    }
                    break;
            }
            return 0;
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override bool CanSeek
        {
            get { if (mBaseStream == null) return base.CanSeek; else return mBaseStream.CanSeek; }
        }

        public override bool CanTimeout
        {
            get
            {
                if (mBaseStream == null) return base.CanTimeout; else return mBaseStream.CanTimeout;
            }
        }

        public override void Flush()
        {
            if (mBaseStream == null) base.Flush(); else mBaseStream.Flush();
        }

        public override long Length
        {
            get { return mLength; }
        }

        public override long Position
        {
            get
            {
                if (mBaseStream == null) 
                    return base.Position - mStartOffset; 
                else
                    return mBaseStream.Position - mStartOffset;
            }
            set
            {
                BSeek(Position, SeekOrigin.Begin);
            }
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return BSeek(offset, origin);
        }

        public override void SetLength(long value)
        {
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            //int MaxRead = count;
            //if (offset + count > (int)(mLength)) MaxRead -= ((offset + count) - (int)mLength);

            //return mBaseStream.Read(buffer, offset + (int)mStartOffset, MaxRead);
            if (mBaseStream == null)
                return base.Read(buffer, offset, count);
            else
                return mBaseStream.Read(buffer, offset, count);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
        }

        public override void Close()
        {
            if (mBaseStream == null)
                base.Close();
            else
                mBaseStream.Close();
        }

        public FileStream BaseStream
        { get { return mBaseStream; } }
    }
}
